﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace UtilLib.OS
{
	/// <summary>
	/// 电源控制：重启、注销、 关机
	/// </summary>
	/// <see cref="http://www.cnblogs.com/TianFang/archive/2008/08/16/1269115.html"/>
	public static class Power
	{
		public static void Reboot()
		{
			DoExitWin(EWX_FORCE | EWX_REBOOT);
		}

		public static void PowerOff()
		{
			DoExitWin(EWX_FORCE | EWX_POWEROFF);
		}

		public static void LogOff()
		{
			DoExitWin(EWX_FORCE | EWX_LOGOFF);
		}

		private static void DoExitWin(int DoFlag)
		{
			bool ok;
			TokPriv1Luid tp;
			IntPtr hproc = GetCurrentProcess();
			IntPtr htok = IntPtr.Zero;
			ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
			tp.Count = 1;
			tp.Luid = 0;
			tp.Attr = SE_PRIVILEGE_ENABLED;
			ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
			ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
			ok = ExitWindowsEx(DoFlag, 0);
		}

		#region WinAPI

		[DllImport("kernel32.dll", ExactSpelling = true)]
		static extern IntPtr GetCurrentProcess();

		[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
		static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

		[DllImport("advapi32.dll", SetLastError = true)]
		static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

		[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
		static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

		[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
		static extern bool ExitWindowsEx(int DoFlag, int rea);

		const int SE_PRIVILEGE_ENABLED = 0x00000002;
		const int TOKEN_QUERY = 0x00000008;
		const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
		const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
		const int EWX_LOGOFF = 0x00000000;
		const int EWX_SHUTDOWN = 0x00000001;
		const int EWX_REBOOT = 0x00000002;
		const int EWX_FORCE = 0x00000004;
		const int EWX_POWEROFF = 0x00000008;
		const int EWX_FORCEIFHUNG = 0x00000010;

		[StructLayout(LayoutKind.Sequential, Pack = 1)]
		internal struct TokPriv1Luid
		{
			public int Count;
			public long Luid;
			public int Attr;
		}

		#endregion
	}


}
